﻿using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace 串口助手
{
    class DataTypeConversion
    {
        /// <summary>
        /// 从字符串中提取整数。
        /// </summary>
        /// <param name="str">待提取的字符串。</param>
        /// <returns>提取出的整数，提取失败时返回 0。</returns>
        public int GetStringNumber(string str)
        {
            try
            {
                // 匹配非数字字符的正则表达式
                string pattern = @"[^0-9]+";
                Regex rgx = new Regex(pattern);
                // 替换非数字字符并转换为整数
                return Convert.ToInt32(rgx.Replace(str, ""));
            }
            catch
            {
                // 如果发生异常，则返回 0
            }
            return 0;
        }

        /// <summary>
        /// 从字符串中提取浮点数。
        /// </summary>
        /// <param name="str">待提取的字符串。</param>
        /// <param name="value">提取出的浮点数，将通过引用返回。</param>
        /// <returns>如果成功提取浮点数返回 true，否则返回 false。</returns>
        public bool GetStringSingle(string str, ref float value)
        {
            // 定义正则表达式以匹配浮点数
            Regex r = new Regex(@"\d*\.\d*|0\.\d*[1-9]\d*$");
            string[] s = new string[] { r.Match(str).Value, r.Replace(str, "") };

            // 如果找到有效的浮点数
            if (s[0] != "" && s[0] != ".")
            {
                value = Convert.ToSingle(s[0]); // 转换并赋值
                return true;
            }
            else if (s.Length > 1 && s[1] != "")
            {
                // 在剩余字符串中查找整数
                Regex regex = new Regex("[0-9]+", RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromSeconds(2));
                MatchCollection mc = regex.Matches(s[1]);
                if (mc.Count > 0)
                {
                    value = Convert.ToSingle(mc[0].Groups[0].Value);
                    return true; // 成功提取
                }
            }
            return false; // 提取失败
        }

        /// <summary>
        /// 计算字节数组的校验和。
        /// </summary>
        /// <param name="data">待计算的字节数组。</param>
        /// <param name="length">字节数组的长度。</param>
        /// <returns>返回校验和。</returns>
        public byte GetByteCheckSum(byte[] data, int length)
        {
            byte cs = 0;
            // 遍历字节数组并累加
            for (int i = 0; i < length; i++)
            {
                cs += data[i];
            }
            return (byte)(~cs); // 返回反码作为校验和
        }

        /// <summary>
        /// 计算 ModBus CRC16 校验码。
        /// </summary>
        /// <param name="data">待计算的字节数组。</param>
        /// <param name="length">字节数组的长度。</param>
        /// <returns>返回计算得到的 CRC16 校验码。</returns>
        public UInt16 GetModBusCRC16(byte[] data, int length)
        {
            int temp;
            UInt16 pos, bit;
            UInt16 crc = 0xFFFF; // 初始化 CRC

            // 遍历字节数组
            for (pos = 0; pos < length; pos++)
            {
                crc = (UInt16)(data[pos] ^ crc); // 计算当前字节与 CRC 的异或
                for (bit = 0; bit < 8; bit++) // 处理每一位
                {
                    temp = crc & 0x1; // 取最低位
                    crc >>= 1; // 右移一位
                    if (temp == 1)
                        crc ^= 0xA001; // 根据最低位的值决定是否与多项式异或
                }
            }
            return crc; // 返回计算得到的 CRC
        }

        /// <summary>
        /// 根据消息尾类型将校验和或 CRC 追加到消息中。
        /// </summary>
        /// <param name="MsgTailType">消息尾类型（如无、CS、ModBus 等）。</param>
        /// <param name="msg">待处理的消息字节数组。</param>
        /// <returns>返回处理后的消息长度。</returns>
        public int ByteAddMsgTail(string MsgTailType, ref byte[] msg)
        {
            byte[] check; // 存放校验数据
            switch (MsgTailType)
            {
                case "无":
                    check = null; // 无校验
                    break;
                case "CS":
                    check = new byte[1];
                    check[0] = GetByteCheckSum(msg, msg.Length); // 计算校验和
                    break;
                case "ModBus":
                    UInt16 crc = GetModBusCRC16(msg, msg.Length); // 计算 ModBus CRC
                    check = new byte[2];
                    check[0] = (byte)(crc); // 低字节
                    check[1] = (byte)(crc >> 8); // 高字节
                    break;
                default:
                    // 将自定义消息尾字符串转换为字节数组
                    check = StringToByte("HEX", MsgTailType);
                    break;
            }

            // 如果校验数据不为空，则将其添加到消息末尾
            if (check != null)
            {
                int TxBufLen = msg.Length; // 原消息长度
                Array.Resize<byte>(ref msg, TxBufLen + check.Length); // 扩展消息数组
                Array.Copy(check, 0, msg, TxBufLen, check.Length); // 复制校验数据
            }
            return msg.Length; // 返回新消息长度
        }

        /// <summary>
        /// 字符串转换为字节数组。
        /// </summary>
        /// <param name="data_type">数据类型（ASCII 或 HEX）。</param>
        /// <param name="data">待转换的字符串。</param>
        /// <returns>返回转换后的字节数组。</returns>
        public byte[] StringToByte(string data_type, string data)
        {
            try
            {
                byte[] buf;
                if (data_type == "ASCII")
                {
                    buf = Encoding.Default.GetBytes(data); // 直接转换为 ASCII 字节数组
                }
                else
                {
                    int i = 0, length, len;
                    string replacement = "";
                    Regex rgx = new Regex(@"\s"); // 去除空格
                    string str = rgx.Replace(data, replacement);

                    // 计算转换后的字节数组长度
                    length = (str.Length - str.Length % 2) / 2;
                    len = length;
                    if (str.Length % 2 != 0)
                        len++;
                    buf = new byte[len];

                    // 逐个字符转换为十六进制字节
                    for (i = 0; i < length; i++)
                    {
                        buf[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
                    }
                    if (str.Length % 2 != 0)
                    {
                        buf[i] = Convert.ToByte(str.Substring(i * 2, 1), 16);
                        length++;
                    }
                }
                return buf; // 返回字节数组
            }
            catch
            {
                // 如果发生异常，则返回 null
            }
            return null;
        }

        /// <summary>
        /// 字节数组转换为字符串。
        /// </summary>
        /// <param name="data_type">数据类型（ASCII 或 HEX）。</param>
        /// <param name="data">待转换的字节数组。</param>
        /// <param name="length">字节数组的有效长度。</param>
        /// <returns>返回转换后的字符串。</returns>
        public string ByteToString(string data_type, byte[] data, int length)
        {
            try
            {
                string s = "";
                if (data_type == "ASCII")
                {
                    s = Encoding.Default.GetString(data, 0, length); // 直接转换为 ASCII 字符串
                }
                else
                {
                    // 将字节数组转换为十六进制字符串，并去掉 "-" 符号
                    s = BitConverter.ToString(data.Skip(0).Take(length).ToArray()).Replace("-", " ");
                }
                return s; // 返回字符串
            }
            catch
            {
                // 如果发生异常，则返回空字符串
            }
            return "";
        }
    }
}
